package com.xunji.standard.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xunji.standard.common.Constant;
import com.xunji.standard.common.R;
import com.xunji.standard.dto.ExportData;
import com.xunji.standard.entity.*;
import com.xunji.standard.service.*;
import com.xunji.standard.util.DateUtil;
import com.xunji.standard.util.ExecutorUtils;
import com.xunji.standard.util.FileUtil;
import com.xunji.standard.util.RequestContextUtil;
import com.xunji.standard.vo.rep.*;
import com.xunji.standard.vo.req.*;
import com.xunji.standard.zip.AdvancedCompressionUtils;
import com.xunji.standard.zip.ExcelCompressionUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @Author: xuqiang_imyours
 * @Date: 2025/6/18 14:44
 * @Description:
 **/
@Slf4j
@Api(tags = "案件管理")
@RestController
@RequestMapping("/case")
public class CaseController {
    @Resource
    CaseService caseService;
    @Resource
    CaseUploadInfoService caseUploadInfoService;
    @Value("${project_temp_path:}")
    private String projectTempPath;
    @Resource
    private CaseFileService caseFileService;
    @Resource
    private TXjNdFlPersonInformationService ndPersonInformationService;
    @Resource
    private NdAnalysisDataService ndAnalysisDataService;
    @Resource
    CaseShareService caseShareService;


    @GetMapping("/list")
    @ApiOperation(value = "案件列表", notes = "案件列表")
    public R list(HttpServletRequest request) {
        String userId = RequestContextUtil.getUser(request);
        if (StringUtils.isEmpty(userId)) return R.failure("请先登录！");
        if (StringUtils.isEmpty(userId)) return R.failure("token凭据无效，请重新登录！");
        List<StCase> cases = caseService.getListByUserId(userId);
        return R.success(cases);
    }

    @PostMapping("/update")
    @ApiOperation(value = "案件更名", notes = "案件更名")
    public R updateCaseName(HttpServletRequest request, @RequestBody StCaseUpdateRequest stCase) {
        if (stCase == null || StringUtils.isEmpty(stCase.getCaseId()) || StringUtils.isEmpty(stCase.getName()))
            return R.failure("参数错误！");
        caseService.updateCaseName(stCase.getCaseId(), stCase.getName());
        return R.success();
    }

    @DeleteMapping("/delete/{caseId}")
    @ApiOperation(value = "案件删除", notes = "案件删除")
    public R deleteCase(@PathVariable String caseId) {
        try {
//            caseService.deleteCase(caseId);
            caseService.logicalDeleteCase(caseId);
            // 删除案件分享
            caseShareService.deleteByCaseId(caseId);
            return R.success();
        } catch (Exception e) {
            log.error("案件删除失败，e->{}", e);
            return R.failure("案件删除失败");
        }
    }

    @GetMapping("/status/{caseId}")
    @ApiOperation(value = "案件状态 3 上传引导 0 解析完成 1 文件解密中 2 文件解析中", notes = "案件状态")
    public R getCaseStatus(@PathVariable String caseId) {

        // 取出所有上传号
        List<CaseUploadInfo> infos = caseUploadInfoService.getListByCaseId(caseId);
        if (infos == null || infos.isEmpty()) return R.success(Constant.I_THREE);
        // 取出倒排第一个,判断状态
        CaseUploadInfo info = infos.get(0);
        Integer status = info.getStatus();
        Long infoId = info.getId();

        if (status == Constant.I_TWO) {
            List<NdAnalysisData> list = ndAnalysisDataService.getListByInfoIdAndCaseId(caseId, infoId);
            if (list != null && !list.isEmpty()) {
                NdAnalysisData ndAnalysisData = list.get(0);
                if (ndAnalysisData.getJxzt() == Constant.I_ONE) {
                    // 说明南大解析已结束
                    // 更新上传号状态
                    caseUploadInfoService.updateStatusById(infoId, Constant.I_ZERO);
                    return R.success(Constant.I_ZERO); // 返回成功状态
                }
            }
        }
        return R.success(status);
    }

    // 上传已读
    @GetMapping("/upload/read")
    @ApiOperation(value = "案件上传已读", notes = "案件上传已读")
    public R uploadRead(@RequestParam String caseId) {
        // 取出所有上传号
        List<CaseUploadInfo> infos = caseUploadInfoService.getListByCaseId(caseId);
        if (infos == null || infos.isEmpty()) return R.success(false);
        // 取出倒排第一个,判断状态
        CaseUploadInfo info = infos.get(0);
        int firstRead = info.getFirstRead();
        if (firstRead == Constant.I_ONE) {
            return R.success(true);
        }
        return R.success(false);
    }

    // 案件上传标记已读
    @GetMapping("/upload/read/mark")
    @ApiOperation(value = "案件上传标记已读", notes = "案件上传标记已读")
    public R markRead(@RequestParam String caseId) {
        // 获取案件上传信息
        List<CaseUploadInfo> infos = caseUploadInfoService.getListByCaseId(caseId);
        if (infos == null || infos.isEmpty()) return R.success(false);
        // 获取第一个上传信息
        CaseUploadInfo info = infos.get(0);
        if (info.getFirstRead() == Constant.I_ZERO) {
            // 更新案件上传信息
            caseUploadInfoService.isRead(info.getId());
        }
        return R.success();
    }

    @GetMapping("/can/upload")
    @ApiOperation(value = "是否可以继续上传", notes = "是否可以继续上传")
    public R canUpload(String caseId) {
        boolean allAnalyzed = caseFileService.isAllAnalyzed(caseId);
        return R.success(allAnalyzed);
    }

    // 新建案件
    @GetMapping("/add")
    @ApiOperation(value = "新建案件", notes = "新建案件")
    public R addCase(HttpServletRequest request) {
        // 初始化案件，返回案件信息和案件id即可
        String userId = RequestContextUtil.getUser(request);
        if (StringUtils.isEmpty(userId)) return R.failure("请先登录！");
        // 初始化案件
        StCase stCase = caseService.addCaseByUserId(userId);
        log.info("初始化案件");
        return R.success(stCase);
    }

    @PostMapping("/upload")
    @ApiOperation(value = "文件批量上传", notes = "文件批量上传")
    public R fileUpload(MultipartFile[] files, String caseId) throws IOException {
        StCase stCase = caseService.getCaseById(caseId);
        if (stCase == null) return R.failure("案件不存在！");
        // 将文件保存到指定目录下
        String uploadFilePath = projectTempPath + File.separator + Constant.CASE_FILE + File.separator + stCase.getId() + File.separator + DateUtil.getDateTime() + File.separator + Constant.XUNJI + File.separator;
        new File(uploadFilePath).mkdir(); // 创建文件夹
        caseService.updateByEntity(stCase);
        // 上传号信息记录
        Long infoId = caseUploadInfoService.add(stCase.getId(), uploadFilePath);
        log.info("初始化上传号");
        for (MultipartFile file : files) {
            FileUtil.copyFileByInput(file.getInputStream(), uploadFilePath + file.getOriginalFilename());
        }
        log.info("文件上传完成！");
        caseService.doProcess(stCase.getId(), infoId, uploadFilePath, null);
        return R.success();
    }

    /*@PostMapping("/keep/upload/{caseId}")
    @ApiOperation(value = "案件文件续传", notes = "案件文件续传")
    public R keepUpload(HttpServletRequest request, @PathVariable String caseId, MultipartFile[] files) throws IOException {
        String userId = RequestContextUtil.getUser(request);
        if (StringUtils.isEmpty(userId)) return R.failure("请先登录！");
        // 校验文件
        if (files == null || files.length == 0) return R.failure("文件不能为空！");
        log.info("案件文件续传,文件上传个数:{}", files.length);
        StCase stCase = caseService.getCaseById(caseId);
        if (stCase == null) return R.failure("案件不存在或已被删除!");

        // 将文件保存到指定目录下
        String uploadFilePath = projectTempPath + File.separator + Constant.CASE_FILE + File.separator + stCase.getId() + File.separator + DateUtil.getDateTime() + File.separator + Constant.XUNJI + File.separator;
        new File(uploadFilePath).mkdir(); // 创建文件夹
        // 上传号信息记录
        Long infoId = caseUploadInfoService.add(stCase.getId(), uploadFilePath);
        for (MultipartFile file : files) {
            FileUtil.copyFileByInput(file.getInputStream(), uploadFilePath + file.getOriginalFilename());
        }
        log.info("文件上传完成！");
        caseService.doProcess(stCase.getId(), infoId, uploadFilePath, null);
        return R.success();
    }*/

    @PostMapping("/file/list")
    @ApiOperation(value = "已上传文件解析列表", notes = "已上传文件解析列表")
    public R getFileList(HttpServletRequest request, @RequestBody CaseFileListPageRequest pageRequest) {
        StCase stCase = caseService.getCaseById(pageRequest.getCaseId());
        if (stCase == null) return R.failure("案件不存在！");
        List<CaseUploadInfo> lists = caseUploadInfoService.getListByCaseId(pageRequest.getCaseId());
        ArrayList<Long> infoIds = new ArrayList<>();

        int isPage = pageRequest.getIsPage(); // 是否分页
        if (isPage == 0) {
            for (CaseUploadInfo info : lists) {
                infoIds.add(info.getId());
            }
            Page<CaseFile> caseFilePage = caseFileService.listPageFilesByInfos(pageRequest.getFileStatus(), infoIds, pageRequest.getPageNumber(), pageRequest.getPageSize());
            if (caseFilePage != null) {
                Page<CaseFileResponse> page = new Page<>();
                ArrayList<CaseFileResponse> caseFileResponses = new ArrayList<>();
                List<CaseFile> records = caseFilePage.getRecords();
                for (CaseFile file : records) {
                    CaseFileResponse cs = CaseFileResponse.getCaseFileResponse(file);
                    caseFileResponses.add(cs);
                }
                page.setCurrent(caseFilePage.getCurrent());
                page.setSize(caseFilePage.getSize());
                page.setTotal(caseFilePage.getTotal());
                page.setRecords(caseFileResponses);
                return R.success(page);
            }
        } else {
            // 不分页， 则查询最新的infoId解析列表
            CaseUploadInfo info = lists.get(0);
            infoIds.add(info.getId());
            List<CaseFile> caseFiles = caseFileService.listPageFilesByInfos(pageRequest.getFileStatus(), infoIds);
            ArrayList<CaseFileResponse> caseFileResponses = new ArrayList<>();
            for (CaseFile file : caseFiles) {
                CaseFileResponse cs = CaseFileResponse.getCaseFileResponse(file);
                caseFileResponses.add(cs);
            }
            return R.success(caseFileResponses);
        }
        return R.success();
    }

    @GetMapping("/file/number")
    @ApiOperation(value = "已上传文件数量统计", notes = "已上传文件数量统计")
    public R getFileNumber(String caseId) {
        StCase stCase = caseService.getCaseById(caseId);
        if (stCase == null) return R.failure("案件不存在！");
        List<CaseUploadInfo> lists = caseUploadInfoService.getListByCaseId(caseId);
        ArrayList<Long> infoIds = new ArrayList<>();
        for (CaseUploadInfo info : lists) {
            infoIds.add(info.getId());
        }
        long sucNumber = caseFileService.getCountByFileStatus(infoIds, Constant.S_ONE); // 成功数量
        long faiNumber = caseFileService.getCountByFileStatus(infoIds, Constant.S_TWO); // 失败数量
        CaseFileAcountResponse response = new CaseFileAcountResponse();
        response.setTotal(sucNumber + faiNumber);
        response.setSucNumber(sucNumber);
        response.setFaiNumber(faiNumber);
        return R.success(response);
    }

    @PostMapping("/file")
    @ApiOperation(value = "删除文件", notes = "删除文件")
    public R deleteFile(@RequestBody CaseFileDeleteRequest request) {
        Long infoId = 0L;
        if (request != null) {
            for (String id : request.getIds()) {
                CaseFile caseFile = caseFileService.getCaseFileById(id);
                if (caseFile == null) continue; // 跳过空数据
                infoId = caseFile.getInfoId();
                // 删除文件
                new File(caseFile.getOriginalPath()).delete(); // 删除原始文件
                caseFileService.deleteById(id); // 删除数据库记录
            }
        }

        CaseUploadInfo uploadInfo = caseUploadInfoService.getById(infoId);
        if (uploadInfo != null) {
            // 添加校验，判断是否全部解密完成
            boolean allAnalyzed = caseFileService.isAllAnalyzed(uploadInfo.getCaseId());
            if (allAnalyzed) {
                List<CaseUploadInfo> lists2 = caseUploadInfoService.getListByCaseId(uploadInfo.getCaseId());
                for (CaseUploadInfo info : lists2) {

                    if (Constant.S_ZERO.equals(info.getIsSend())) {
                        // 变更上传号状态
                        caseUploadInfoService.updateStatusById(info.getId(), Constant.I_TWO);

                        ExecutorUtils.execute(() -> {
                            caseService.doParse(uploadInfo.getCaseId(), info.getId());
                        });
                    }
                }
            }
        }

        return R.success();
    }


    @PostMapping("/analysis/file")
    @ApiOperation(value = "解析密码文件", notes = "解析密码文件")
    public R zipFile(@RequestBody UnzipFileRequest unzipFileRequest) throws IOException {
        // 参数校验
        String password = unzipFileRequest.getPassword();
        if (StringUtils.isEmpty(unzipFileRequest.getId())) return R.failure("参数不合法！");
        if (StringUtils.isEmpty(password)) return R.failure("密码不能为空！");
        String id = unzipFileRequest.getId();
        CaseFile caseFile = caseFileService.getCaseFileById(id);
        if (caseFile == null) return R.failure("文件不存在或已被删除");
        CaseUploadInfo uploadInfo = caseUploadInfoService.getById(caseFile.getInfoId());
        String uploadPath = uploadInfo.getUploadPath(); // 文件保存跟路径
        String fileType = caseFile.getFileType();
        String caseId = caseFile.getCaseId();
        Long infoId = caseFile.getInfoId();
        // 同步接口处理
        if (fileType.equals(Constant.S_TWO)) {
            log.info("压缩包密码解压，当前压缩包名称：{}，密码{}", caseFile.getOriginalPath(), password);
            // 判断文件是否能解压
            String originalPath = caseFile.getOriginalPath();
            if (Files.exists(Paths.get(originalPath))) {
                // 解压到系统临时目录下
                log.info("尝试解压压缩包,解压到临时目录:{}", System.getProperty("java.io.tmpdir"));
                int decompress = AdvancedCompressionUtils.decompress(originalPath, System.getProperty("java.io.tmpdir"), password.toCharArray());
                if (decompress != 0) {
                    return R.failure("解压失败！");
                }
                // 压缩包密码解压
                /*List<File> files = doZipWithPassword(caseFile, password);
                if (files == null || files.isEmpty()) {
                    return R.failure("解压失败！");
                }*/
                // 尝试解压成功，需删除原始记录
                caseFileService.deleteByCaseIdAndInfoId(caseId, infoId);

                // 重新解析一遍
                caseService.doProcess(caseId, infoId, uploadPath, password);
            }
        } else if (fileType.equals(Constant.S_ONE)) {
            // 调研excel是否能成功读取
            String originalPath = caseFile.getOriginalPath();
            log.info("excel密码解压，当前excel名称：{}，密码{}", originalPath, password);
            boolean res = ExcelCompressionUtils.isExcelEncrypted(originalPath, password);
            log.info("excel解密结果：{}", res);
            if (res) { // 密码尝试成功
                caseFileService.updateExcelPassword(originalPath, caseFile, password);
            } else {
                return R.failure("密码不正确！");
            }
        }

        // 添加校验，判断是否全部解密完成
        boolean allAnalyzed = caseFileService.isAllAnalyzed(uploadInfo.getCaseId());
        if (allAnalyzed) {
            List<CaseUploadInfo> lists2 = caseUploadInfoService.getListByCaseId(uploadInfo.getCaseId());
            for (CaseUploadInfo info : lists2) {
                if (Constant.S_ZERO.equals(info.getIsSend())) {
                    // 变更上传号状态
                    caseUploadInfoService.updateStatusById(info.getId(), Constant.I_TWO);

                    ExecutorUtils.execute(() -> {
                        caseService.doParse(uploadInfo.getCaseId(), info.getId());
                    });
                }
            }
        }
        return R.success();
    }

    // 数据清洗列表查询
    @PostMapping("/analysis/list")
    @ApiOperation(value = "数据清洗列表查询1.0", notes = "数据清洗列表查询1.0")
    public R getAnalysisList(HttpServletRequest request, @RequestBody CaseAnalysisListRequest listRequest) {
        String caseId = listRequest.getCaseId();
        if (StringUtils.isEmpty(caseId)) return R.success(null);
        // 查询人员信息表
        log.info("开始查询人员信息表");
        List<TXjNdFlPersonInformation> persons = ndPersonInformationService.selectListByCaseId(caseId, listRequest.getKeyword());
        log.info("查询到人员信息表：{}", persons);
        persons = deduplicatePersons(persons);
        List<CaseAnalysisListResponse> responses = caseService.doPageInformation(persons, listRequest.getType());

        Page<CaseAnalysisListResponse> donePage = doPage(responses, listRequest.getPageNum(), listRequest.getPageSize());

        return R.success(donePage);
    }

    @PostMapping("/analysis/list2")
    @ApiOperation(value = "数据清洗列表查询2.0", notes = "数据清洗列表查询2.0")
    public R getAnalysisList2(HttpServletRequest request, @RequestBody CaseAnalysisListRequest2 listRequest) {
        String caseId = listRequest.getCaseId();
        if (StringUtils.isEmpty(caseId)) return R.success(null);
        // 查询人员信息表
        log.info("开始查询人员信息表");
        List<TXjNdFlPersonInformation> persons = ndPersonInformationService.selectListByCaseId(caseId, listRequest.getKeyword());
        log.info("查询到人员信息表：{}", persons);
        persons = deduplicatePersons(persons);

        List<CaseAnalysisListResponse2> responses = caseService.doPageInformation2(persons, listRequest.getCaseId());
        Page<CaseAnalysisListResponse2> donePage = doPage(responses, listRequest.getPageNum(), listRequest.getPageSize());
        return R.success(donePage);
    }


    // 个人信息查询
    @GetMapping("/analysis/person/info/view")
    @ApiOperation(value = "个人档案", notes = "个人档案")
    public R getPersonInfo(@RequestParam String caseId, @RequestParam Long personId) {
        CasePersonInformationResponse response = caseService.doInformationInfo(caseId, personId);
        return R.success(response);
    }

    // 数据统计接口
    @GetMapping("/data/statistics")
    @ApiOperation(value = "数据统计接口", notes = "数据统计接口")
    public R getDataStatistics(@RequestParam String caseId) {
        DataStatisticsResponse response = caseService.dataStatistics(caseId);
        return R.success(response);
    }

    // 归属人查询
    @GetMapping("/owner/view")
    @ApiOperation(value = "归属人查询", notes = "归属人查询")
    public R getOwnerInfo(@RequestParam String caseId) {
        // 查询人员信息表
        List<TXjNdFlPersonInformation> persons = ndPersonInformationService.selectListByCaseId(caseId, null);
        persons = deduplicatePersons(persons);
        return R.success(persons);
    }

    // 归属人信息修改
    @PostMapping("/owner/update/")
    @ApiOperation(value = "归属人信息修改", notes = "归属人信息修改")
    public R updateOwnerInfo(@RequestBody CaseOwnerUpdateRequest request) {
        caseService.updateOwnerInfo(request);
        return R.success();
    }

    /**
     * 对列表数据进行内存分页处理
     *
     * @param dataList 原始数据列表
     * @param pageNum  页码（从1开始）
     * @param pageSize 每页大小
     * @param <T>      数据类型
     * @return 分页结果
     */
    private <T> Page<T> doPage(List<T> dataList, int pageNum, int pageSize) {
        int total = dataList.size();

        // 计算分页索引
        int startIndex = (pageNum - 1) * pageSize;
        int endIndex = Math.min(startIndex + pageSize, total);

        // 处理边界情况
        if (startIndex >= total) {
            startIndex = total;
            endIndex = total;
        }

        // 内存分页处理
        List<T> pagedList = dataList.subList(startIndex, endIndex);

        // 构建分页对象
        Page<T> page = new Page<>(pageNum, pageSize);
        page.setRecords(pagedList);
        page.setTotal(total);
        page.setCurrent(pageNum);
        page.setSize(pageSize);

        return page;
    }


    // 数据清洗列表人员删除
    @PostMapping("/analysis/delete")
    @ApiOperation(value = "数据清洗列表人员删除", notes = "数据清洗列表人员删除")
    public R deleteAnalysisList(@RequestBody CaseAnalysisDeleteRequest request) {
        String caseId = request.getCaseId();
        if (StringUtils.isEmpty(caseId) || request.getDeleteData() == null || request.getDeleteData().isEmpty())
            return R.failure("参数错误");
        StCase stCase = caseService.getCaseById(caseId);
        if (stCase == null) return R.failure("案件不存在");

        for (ExportData data : request.getDeleteData()) {
            String xm = data.getXm();
            String sfzh = data.getSfzh();
            Integer type = data.getType();
            if (!StringUtils.isEmpty(xm) && !StringUtils.isEmpty(sfzh)) {
                caseService.deleteAnalysisPerson(caseId, xm, sfzh, type); // 删除人员信息表数据
            }
        }
        return R.success();
    }

    private List<File> doZipWithPassword(CaseFile caseFile, String password) {
        // 找到当前文件统计存在多少文件（去除自身）
        String originalPath = caseFile.getOriginalPath();
        File chFile = new File(originalPath);
        File paFile = new File(chFile.getParent()); // 父类文件对象
        String absolutePath = paFile.getAbsolutePath();
        try {
            return AdvancedCompressionUtils.unzipAndGetContents(originalPath, absolutePath, password.toCharArray());
        } catch (Exception e) {
            log.error("文件解压异常，解压失败");
        }
        return null;
    }

    /**
     * 对人员信息列表进行去重处理，基于姓名和身份证号组合去重
     *
     * @param persons 人员信息列表
     * @return 去重后的人员信息列表
     */
    private List<TXjNdFlPersonInformation> deduplicatePersons(List<TXjNdFlPersonInformation> persons) {
        if (persons == null) {
            return null;
        }
        HashMap<String, TXjNdFlPersonInformation> map = new HashMap<>();
        for (TXjNdFlPersonInformation person : persons) {
            String key = person.getXm() + person.getSfzh();
            if (!map.containsKey(key)) {
                map.put(key, person);
            }
        }
        return new ArrayList<>(map.values());
    }


}
